# blib/utils.py
#
#

""" and stuff. """

## =======
## IMPORTS
## =======

## basic imports

import traceback
import datetime
import optparse
import hashlib
import logging
import string
import time
import sys
import os
import re

## =========
## CONSTANTS
## =========

attributes = {}
subelements = {}

attributes['message'] = ['type', 'from', 'to', 'id']
subelements['message'] = ['subject', 'body', 'error', 'thread', 'x']

attributes['presence'] = ['type', 'from', 'to', 'id']
subelements['presence'] = ['show', 'status', 'priority', 'x']


attributes['iq'] = ['type', 'from', 'to', 'id']
subelements['iq'] = ['query', 'error']

## ===========
## DEFINITIONS
## ===========

## time related 

timere = re.compile('(\S+)\s+(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)')
bdmonths = ['Bo', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

## dir manipulation variables

dirmask = 0o700 
filemask = 0o600
allowedchars = string.ascii_letters + string.digits + "_,-. \n" + string.punctuation

options = [
              ('-s', '--shell', 'store_true', False, 'doshell',  "enable shell prompting"),
              ('-a', '--api', 'store_true', False, 'api',  "enable api server"),
              ('-t', '--test', 'store_true', False, 'do_test',  "enable test mode"),
              ('', '--local', 'store_true', False, 'do_local',  "use local directory as the working directory"),
              ('', '--apiport', 'string', "", 'apiport', "port on which the api server will run"),
              ('-d', '--dir', 'string', "", 'workdir',  "directory to work with"),   
              ('-l', '--loglevel', 'string', "", 'loglevel',  "loglevel"),
              ('-c', '--channel', 'string', "", 'channel',  "channel"),
          ]

## ==================
## SIGNATURE FUNCTION
## ==================

def make_signature(data): return str(hashlib.sha1(bytes(str(data), "utf-8")).hexdigest())

## ===============
## ERROR FUNCTIONS
## ===============

def error(*args, **kwargs):
    msg = exceptionmsg()
    logging.error("error detected:\n\n%s\n" % msg)
    return msg

## exceptionmsg function

def exceptionmsg(*args, **kwargs):
    exctype, excvalue, tb = sys.exc_info()
    trace = traceback.extract_tb(tb)
    result = ""
    for i in trace:
        fname = i[0]
        linenr = i[1]
        func = i[2]  
        plugfile = fname[:-3].split(os.sep)
        mod = []
        for i in plugfile[::-1]: mod.append(i)
        ownname = '.'.join(mod[::-1])
        result += "%s:%s %s | " % (ownname, linenr, func)
    del trace
    return "%s%s: %s" % (result, exctype, excvalue)

## ===============
## PRIMARY HELPERS
## ===============

## isvar function

def isO(obj): return isinstance(obj, O) 

## splitted function

def stripped(input):
    try: return input.split("/")[0]
    except: return input

## get_subs function

def get_subs(input, regex): return re.findall(regex, input)

## get_method function

def get_method(obj):
    txt = str(obj)
    return ".".join(get_subs(txt, "method (.*?) of"))

## get_classfromstring function

def get_clsfromstring(typestr):
    subs = get_subs(typestr, "'(.*?)'")
    return subs[0].split(".")[-1]

## get_clsname function

def get_clsname(obj):
    name = get_name(obj)
    return name.split(".")[-1]

## get_name function - retrieve usable name from repr

def get_name(obj):
    txt = str(obj)
    res = ".".join(get_subs(txt, "(method .*?) of"))
    if not res: res = ".".join(get_subs(txt, "(function .*?) at"))
    if not res: txt = str(type(obj)) ; res = ".".join(get_subs(txt, "'(.*?)'"))
    return res.replace(" ", ".")

## j function - joining lists into paths

def j(*args):
     if not args: return
     todo = list(map(str, filter(None, args)))
     return os.path.join(*todo)

def mj(*args):
     if not args: return
     todo = list(map(str, filter(None, args)))
     return os.path.join(*todo).replace(os.sep, ".")

def dj(*args):
     if not args: return
     todo = list(map(str, filter(None, args)))
     return os.path.join(*todo).replace(os.sep, "-")

## aj function - absolute paths

def aj(sep=None, *args): return os.path.abspath(*j(sep, *args))

## =================
## RESOLVE FUNCTIONS
## =================

## resolve_ip function

def resolve_ip(hostname=None, timeout=1.0):
    oldtimeout = socket.getdefaulttimeout()
    socket.setdefaulttimeout(timeout)
    try: ip = socket.gethostbyname(hostname or socket.gethostname())
    except socket.timeout: ip = None
    socket.setdefaulttimeout(oldtimeout)
    return ip

## resolve_host function

def resolve_host(ip=None, timeout=1.0):
    """ determine the ip address we are running on, we use this for creatin an id. """
    oldtimeout = socket.getdefaulttimeout()
    socket.setdefaulttimeout(timeout)
    try: host = socket.gethostbyaddr(ip or resolve_ip())[0]
    except socket.timeout: host = None
    socket.setdefaulttimeout(oldtimeout)
    return host

## ===================
## DIRECTORY FUNCTIONS
## ===================

## touch function

def touch(fname):
    try: fd = os.open(fname, os.O_RDONLY | os.O_CREAT) ; os.close(fd)
    except: error()

## check_permission function

def check_permissions(ddir, dirmask=dirmask, filemask=filemask):
    uid = os.getuid()
    gid = os.getgid()
    try: stat = os.stat(ddir)
    except OSError: make_dir(ddir) ; stat = os.stat(ddir) 
    if stat.st_uid != uid: os.chown(ddir, uid, gid)
    if os.path.isfile(ddir): mask = filemask
    else: mask = dirmask
    if stat.st_mode != mask: os.chmod(ddir, mask)

## make_dir function

def make_dir(path):
    if not path.endswith(os.sep): path, fn = os.path.split(path)
    target = os.sep
    for item in path.split(os.sep):
        if not item: continue
        target = j(target, item, "")
        if not os.path.isdir(target):
            try:
                os.mkdir(target)
                check_permissions(target)
            except OSError as ex: logging.debug(ex) ; continue 
    return path

## ====================
## STACKFRAME FUNCTIONS
## ====================

## dump_frame function

def dump_frame(search="code"):
    result = {}
    frame = sys._getframe(1)
    search = str(search)
    for i in dir(frame):
        if search in i:
            target = getattr(frame, i)
            for j in dir(target):
                result[j] = getattr(target, j)
    return result

## called_from function

def called_from(level=2):
    """ walk the callstack until string is found. stop when toplevel wtf package is found. """
    result = ""  
    loopframe = sys._getframe(level)
    if not loopframe: return result
    marker = ""
    pre = "core"
    while 1:
        try: back = loopframe.f_back
        except AttributeError: break
        if not back: break
        filename = back.f_code.co_filename
        if "plugs" in filename: result = filename.split(os.sep)[-1][:-3] ; pre = "plugs" ; break
        loopframe = back
    del loopframe   
    if result: return "%s.%s" % (pre, result)

## =============
## FILE LOCATION
## =============

## get_source function

def get_source(mod):
    """ return the directory a module is coming from. """
    if not os.getcwd() in sys.path: sys.path.insert(0, os.getcwd())
    source = None
    splitted = mod.split(".")
    if len(splitted) == 1: splitted.append("")
    thedir, file = os.path.split(mod.replace(".", os.sep))
    if os.path.isdir(thedir): source = thedir
    if source and os.path.exists(source): logging.info("source is %s" % source) ; return source
    if not source:
        try: import pkg_resources
        except (ImportError, ValueError): import wtf.contrib.pkg_resources
        source = p.resource_filename()
    logging.info("source is %s" % source)
    return source

## ==============
## FILENAME STUFF
## ==============

## stripbadchar function

def stripbadchar(s): return "".join([c for c in s if ord(c) > 31 or c in allowedchars])

## enc_char function

def enc_char(s):
    result = []
    for c in s:
        if c in allowedchars: result.append(c)
        else: result.append(enc_name(c))
    return "".join(result)

## enc_needed function

def enc_needed(s): return [c for c in s if c not in allowedchars]

## enc_name function

def enc_name(input): return str(base64.urlsafe_b64encode(bytes(input, "utf-8")), "utf-8")

## split_txt function - make portions 

def split_txt(what, l=375):
    txtlist = []
    start = 0
    end = l
    length = len(what)
    for i in range(int(length/end+1)):
        starttag = what.find("</", end)
        if starttag != -1: endword = what.find('>', end) + 1
        else:
            endword = what.find(' ', end)
            if endword == -1: endword = length
        res = what[start:endword]
        if res: txtlist.append(res)
        start = endword
        end = start + l
    return txtlist

## lock_dec function

def lock_dec(lock):
    def locked(func):
        """ locking function """
        def lockedfunc(*args, **kwargs):
            """ the locked function. """
            lock.acquire()
            try: return func(*args, **kwargs)
            finally: lock.release()

        return lockedfunc

    return locked

## completa function

completions = {}

def completer(text, state):
    try: matches = completions[text]
    except KeyError: matches[state] = cmnds.list_keys(want=text)
    try: return matches[state]
    except: return None

## =====================
## TIME RELATED FUCTIONS
## =====================

## striptime function

def striptime(what):  
    what = str(what)
    what = re.sub('\d+-\d+-\d+', '', what)
    what = re.sub('\d+-\d+', '', what)
    what = re.sub('\d+:\d+', '', what)
    what = re.sub('\s+', ' ', what)
    return what.strip()  

## now function

def now():
    if time.daylight: ttime = time.ctime(time.time() + int(time.timezone) + 3600)
    else: ttime = time.ctime(time.time() + int(time.timezone))
    return ttime

## stamp function

def stamp(timestamp=None):
    now = datetime.datetime.now()
    return str(now.microsecond)

## hms function

def hms(timestamp=None):
    now = datetime.datetime.now()
    #return "%H:%M:%S" % (now.hour, now.minute, now.second)
    return now.time()

## today function

def today(timestamp=None):
    if time.daylight: ttime = time.ctime(timestamp or time.time() + int(time.timezone) + 3600)
    else: ttime = time.ctime(timestamp or time.time() + int(time.timezone))
    matched = re.search(timere, ttime)
    if matched: return "%s-%s-%s" % (matched.group(3), matched.group(2), matched.group(7))

## today_stamp function

def today_stamp(timestamp=None):
    if time.daylight: ttime = time.ctime(time.time() + int(time.timezone) + 3600)
    else: ttime = time.ctime(time.time() + int(time.timezone))
    matched = re.search(timere, ttime)
    if matched:
        temp = "%s %s %s" % (matched.group(3), matched.group(2), matched.group(7))
        timestring = time.strptime(temp, "%d %b %Y")
        result = time.mktime(timestring)
        return result

## strtorepeate function

def strtorepeat(what):
    splitted = what.split()
    for s in splitted:
        try: repeat = int(s[1:]) ; return repeat
        except: pass

## strtotime function

def strtotime(what):
    daymonthyear = 0
    hoursmin = 0
    try:
        dmyre = re.search('(\d+)-(\d+)-(\d+)', str(what))
        if dmyre:
            (day, month, year) = dmyre.groups()
            day = int(day)
            month = int(month)
            year = int(year)
            if day <= calendar.monthrange(year, month)[1]:
                date = "%s %s %s" % (day, bdmonths[month], year)
                daymonthyear = time.mktime(time.strptime(date, "%d %b %Y"))
            else: return None
        else:
            dmre = re.search('(\d+)-(\d+)', str(what))
            if dmre:
                year = time.localtime()[0]
                (day, month) = dmre.groups()
                day = int(day)
                month = int(month)
                if day <= calendar.monthrange(year, month)[1]: 
                    date = "%s %s %s" % (day, bdmonths[month], year)
                    daymonthyear = time.mktime(time.strptime(date, "%d %b %Y"))
                else: return None
        hmsre = re.search('(\d+):(\d+):(\d+)', str(what))
        if hmsre:
            (h, m, s) = hmsre.groups()
            h = int(h)
            m = int(m)
            s = int(s)
            if h > 24 or h < 0 or m > 60 or m < 0 or s > 60 or s < 0: return None
            hours = 60 * 60 * (int(hmsre.group(1)))
            hoursmin = hours  + int(hmsre.group(2)) * 60
            hms = hoursmin + int(hmsre.group(3))
        else:
            hmre = re.search('(\d+):(\d+)', str(what))
            if hmre:
                (h, m) = hmre.groups()
                h = int(h)
                m = int(m)
                if h > 24 or h < 0 or m > 60 or m < 0: return None
                hours = 60 * 60 * (int(hmre.group(1)))
                hms = hours  + int(hmre.group(2)) * 60
            else: hms = 0
        if not daymonthyear and not hms: return None
        if daymonthyear == 0: heute = today()
        else: heute = daymonthyear
        return heute + hms
    except Exception: error()

## headertxt variable

headertxt = '''# %s
#
# this is a blib (v%s) file, %s
#
# blib can edit this file !!

'''
